﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Xml.Linq;
using Microsoft.Office.OneNote.Interop;

namespace Microsoft.Office.OneNote
{
    [DebuggerDisplay("Unfiled Notes")]
    [OneNoteXmlElementAttribute("UnfiledNotes")]
    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unfiled")]
    public sealed class OneNoteUnfiledNotes : OneNoteHierarchyObject, IOneNoteObjectWithChildren
    {
        private bool _sectionIsOpenElsewhere;

        internal OneNoteUnfiledNotes(OneNoteHierarchy hierarchy)
            : base(OneNoteObjectId.Empty)
        {
            // this is the special case, where the unfiled notes section is
            // located in some open notebook. 

            // it means that the hierarchy XML doesn't contain an <UnfiledNotes> element,
            // and we must initialize this object using an existing section object.

            // the Notebooks collection must be fully initialized and updated (including sections)
            // for this to work.

            _sectionIsOpenElsewhere = true;

            Hierarchy = hierarchy;
            ReloadSection();
        }

        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal OneNoteUnfiledNotes(OneNoteObjectId id)
            : base(id)
        {
            // this is the regular case, where the object is loaded
            // by OneNoteHierarchy._storage.

            // it means that the unfiled notes section isn't loaded by
            // a regular notebook and is contained only in the <one:UnfileNotes>
            // element.
        }

        public OneNoteSection Section
        {
            get;
            private set;
        }

        internal bool SectionIsOpenElsewhere
        {
            get { return _sectionIsOpenElsewhere; }
        }

        internal override void OnHierarchyChanged()
        {
            if (Section != null)
            {
                Section.Hierarchy = Hierarchy;
            }
        }

        internal void ReloadSection()
        {
            string path = OneNoteApplication.Current.GetSpecialLocation(SpecialLocation.UnfiledNotesSection);

            if (Section == null || !Section.Path.Equals(path, StringComparison.OrdinalIgnoreCase))
            {
                Section = Hierarchy.OpenSection(path);
            }
        }

        internal override void MarkInvalidOverride()
        {
            base.MarkInvalidOverride();

            if (_sectionIsOpenElsewhere)
            {
                // the contained section must not be invalidated,
                // because it can be safely used from other places.
            }
            else
            {
                Section.MarkInvalid();
            }
        }
        
        void IOneNoteObjectWithChildren.UpdateFrom(IEnumerable<XElement> elements)
        {
            XElement sectionElement = elements.FirstOrDefault();

            if (sectionElement == null)
            {
                if (Section != null)
                {
                    if (!_sectionIsOpenElsewhere)
                    {
                        Section.MarkInvalid();
                        Section = null;
                    }
                }

                return;
            }

            OneNoteObjectId sectionId = OneNoteSchema.GetObjectID(sectionElement);

            if (Section != null)
            {
                if (Section.ObjectId.Equals(sectionId))
                {
                    // the unfiled notes section didn't change since last
                    // update, so we can safely update the old object.

                    OneNoteSchema.Deserialize(Section, sectionElement);
                    return;
                }
                else
                {
                    // the user designated other section as the unfiled notes 
                    // section since the last update. therefore, we need to 
                    // discard the old object.

                    Section.MarkInvalid();
                    Section = null;
                }
            }

            Section = OneNoteObjectFactory.CreateWithIdentity<OneNoteSection>(sectionId);
            Section.Hierarchy = Hierarchy;
            
            OneNoteSchema.Deserialize(Section, sectionElement);
        }
    }
}
